package com.idp.service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.Map;

import com.huaweicloud.sdk.core.auth.GlobalCredentials;
import com.huaweicloud.sdk.core.http.HttpConfig;
import com.huaweicloud.sdk.iam.v3.IamClient;
import com.huaweicloud.sdk.iam.v3.model.*;

/**
 * @Author JTR -H
 * @Address BS_221
 * @Created_Date 2021/8/1 - 15:21
 */
public class CreateCloudLoginUrlSolution {

    private static final int SECURITY_TOKEN_DURATION_MS = 1800;
    private static final int LOGIN_TOKEN_DURATION_MS = SECURITY_TOKEN_DURATION_MS / 2;

    //使用全局域名获取自定义代理登录票据
    String endpoint = "https://iam.myhuaweicloud.com";

    /**
     * 真实请求url: https://iam.cn-east-2.myhuaweicloud.com/v3.0/OS-CREDENTIAL/securitytokens
     *
     * # 字段详解的链接见HUAWEI官网 @{https://support.huaweicloud.com/api-iam/iam_04_0002.html}
     * 请求头:
     *      {
     *       "User-Agent": "API Explorer",
     *       "X-Auth-Token": "***",    # IAM用户token或联邦用户的token或委托token。该参数与请求体中的“auth.identity.token.id”填写其一即可
     *       "Content-Type": "application/json;charset=UTF-8"
     *      }
     * 请求体:
     *      {
     *       "auth": {
     *        "identity": {
     *         "methods": [
     *          "token"
     *         ],
     *         "token": {
     *          "duration_seconds": 900
     *         },
     *         "policy": {          # 用户自定义策略的信息，用于限制获取到的临时访问密钥和securitytoken的权限
     *          "Version": "1.1",
     *          "Statement": [
     *           {
     *            "Action": [
     *             "obs:object:*"
     *            ],
     *            "Effect": "Allow",
     *            "Resource": [
     *             "obs:*:*:object:*"
     *            ]}]}}}}
     * 响应参数:
     *      expires_at: AK/SK和securitytoken的过期时间。响应参数为UTC时间格式，北京时间为UTC+8小时。
     *           如返回: "expires_at": "2020-01-08T02:56:19.587000Z"
     *      access: 获取的临时AK。
     *      secret: 获取的临时SK。
     *      securitytoken: securitytoken是将所获的AK、SK等信息进行加密后的字符串。
     */
    public String createCloudLoginUrl(String enterpriseSystemLoginURL,
                                      String domainId,
                                      String ak,
                                      String sk) throws UnsupportedEncodingException {
        //配置客户端属性
        HttpConfig config = HttpConfig.getDefaultHttpConfig()
                .withIgnoreSSLVerification(true);

        // 使用IAM userB的domainID/ak/sk,初始化指定IAM客户端 {Service}Client,用户B的创建方式见“创建IAM用户”章节
        IamClient iamClient = IamClient.newBuilder().withCredential(new GlobalCredentials()
                .withDomainId(domainId)
                .withAk(ak)
                .withSk(sk)
        )
                .withEndpoint(endpoint)
                .withHttpConfig(config)
                .build();

        /* CreateTemporaryAccessKeyByToken
         * 调用通过token获取临时访问密钥和securitytoken的接口来获取临时SK/AK和securitytoken。
         * 访问秘钥和securitytoken的默认有效期为900秒，即15分钟，取值范围为15分钟-24小时。
         * 注意： 下一步获取自定义代理登录票据logintoken时，如果您设置了有效期，则有效期不能大于这里获取的securitytoken的剩余有效时间。
         * */
        TokenAuthIdentity tokenAuthIdentity = new TokenAuthIdentity()
                .withMethods(Collections.singletonList(TokenAuthIdentity.MethodsEnum.fromValue("token")))
                .withToken(new IdentityToken().withDurationSeconds(SECURITY_TOKEN_DURATION_MS));

        CreateTemporaryAccessKeyByTokenRequest request = new CreateTemporaryAccessKeyByTokenRequest()
                .withBody(new CreateTemporaryAccessKeyByTokenRequestBody()
                        .withAuth(new TokenAuth()
                                .withIdentity(tokenAuthIdentity)));

        /* 该方法返回 response, 格式如下
         * 响应参数:
         *      expires_at: AK/SK和securitytoken的过期时间。响应参数为UTC时间格式，北京时间为UTC+8小时。
         *           如返回: "expires_at": "2020-01-08T02:56:19.587000Z"
         *      access: 获取的临时AK。
         *      secret: 获取的临时SK。
         *      securitytoken: securitytoken是将所获的AK、SK等信息进行加密后的字符串。
         * */
        Credential credential = iamClient
                .createTemporaryAccessKeyByToken(request)   // CreateTemporaryAccessKeyByTokenResponse
                .getCredential();


        /* CreateLoginToken
         * 获取自定义代理登录票据logintoken。
         *
         * 企业IdP自定义代理携带获取到的临时访问密钥和securitytoken通过全局域名（iam.myhuaweicloud.com）调用API
         * （POST /v3.0/OS-AUTH/securitytoken/logintokens）获取登录票据loginToken。登录票据位于Response Header中的X-Subject-LoginToken
         *
         * logintoken是系统颁发给自定义代理用户的登录票据，承载用户的身份、session等信息。
         * 调用自定义代理URL登录云服务控制台时，可以使用本接口获取的logintoken进行认证。
         * 自定义代理登录票据logintoken的有效期默认为600秒，取值范围为10分钟-12小时。
         * 注意：自定义代理登录票据logintoken的有效期不能大于上一步获取的securitytoken的剩余有效时间。
         * */
        CreateLoginTokenRequestBody loginTokenRequestBody = new CreateLoginTokenRequestBody()
                .withAuth(new LoginTokenAuth()
                        .withSecuritytoken(new LoginTokenSecurityToken()
                                .withAccess(credential.getAccess())
                                .withId(credential.getSecuritytoken())
                                .withSecret(credential.getSecret())
                                .withDurationSeconds(LOGIN_TOKEN_DURATION_MS)));

        CreateLoginTokenResponse loginTokenResponse = iamClient
                .createLoginToken(new CreateLoginTokenRequest().withBody(loginTokenRequestBody));
        String loginToken = loginTokenResponse.getXSubjectLoginToken();

        //获取自定义代理登录票据URL
        String authURL = "https://auth.huaweicloud.com/authui/federation/login";
        //企业管理系统登录地址
        // String enterpriseSystemLoginURL
        //需要访问的华为云服务地址
        String targetConsoleURL = "https://console.huaweicloud.com/iam/?region=cn-north-4";

        //创建云服务登录地址FederationProxyUrl，作为Location返回给浏览器。
        String FederationProxyUrl = authURL + "?idp_login_url=" +
                URLEncoder.encode(enterpriseSystemLoginURL, "UTF-8") +
                "&service=" + URLEncoder.encode(targetConsoleURL, "UTF-8") +
                "&logintoken=" + URLEncoder.encode(loginToken, "UTF-8");

        return FederationProxyUrl;
    }

}


/*
 ******************************************************
 *    Eliminate all impossible,                       *
 *    remain that although or else can be thought of, *
 *    discuss,                                        *
 *    that also is a fact.                            *
 ******************************************************
 */
